package org.atlantis.grosbeak.pot.transaction;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import org.atlantis.grosbeak.lang.Exceptions;
import org.atlantis.grosbeak.logger.Logger;
import org.atlantis.grosbeak.logger.LoggerFactory;
import org.atlantis.grosbeak.pot.PotException;
import org.atlantis.grosbeak.pot.PotKit;

/**
 * 事务管理。
 * 
 * @author @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 */
public class Transaction {

	private Logger logger = LoggerFactory.getLogger(Transaction.class);

	private final TransactionProvider txProvider;
	private final Connection connection;
	private boolean rollbackOnly = false;
	private boolean hasRollback = false;

	Transaction(TransactionProvider txProvider) {
		this.txProvider = txProvider;
		this.connection = txProvider.getCurrentConnection();
	}

	/**
	 * 是否可以回滚。
	 * 
	 * @return 如果可以回滚则返回true，否则返回false。
	 */
	public boolean isRollbackOnly() {
		return rollbackOnly;
	}

	/**
	 * 设置当前事务可以回滚。
	 */
	public void setRollbackOnly() {
		this.rollbackOnly = true;
	}

	/**
	 * 得到当前的数据库连接。
	 * 
	 * @return 当前的数据库连接。
	 */
	public Connection getCurrentConnection() {
		return this.connection;
	}

	/**
	 * 直接执行一条SQL语句。
	 * 
	 * @param sql
	 *            需要执行的SQL语句。
	 * @throws PotException
	 *             执行指定SQL语句时可能出现的问题。
	 */
	public boolean shortcut(String sql) throws PotException {
		Statement stat = null;
		try {
			stat = connection.createStatement();
			return stat.execute(sql);
		} catch (SQLException e) {
			throw Exceptions.wrapThrow(PotException.class, e);
		} finally {
			PotKit.safelyClose(stat);
		}
	}

	/**
	 * 回滚当前事务。
	 * 
	 * @throws PotException
	 *             回滚事务可能出现的问题。
	 */
	public void rollback() throws PotException {
		if (hasRollback)
			return;
		hasRollback = true;
		logger.debug("Transaction rollback.");
		try {
			connection.rollback();
		} catch (SQLException e) {
			throw Exceptions.makeThrow(PotException.class, e,
					"Rollback transaction failed.");
		} finally {
			txProvider.clean();
		}
	}

	/**
	 * 提交当前事务。
	 */
	public void commit() {
		if (rollbackOnly) {
			rollback();
			return;
		}
		logger.debug("Transaction commit.");
		try {
			connection.commit();
		} catch (SQLException e) {
			throw Exceptions.makeThrow(PotException.class, e,
					"Commit transaction failed.");
		} finally {
			txProvider.clean();
		}
	}
}